{%-import 'loader.jinja2' as loader-%}

{%-macro Combination(schema)-%}
    {%-if 'allOf' in schema-%}
        allOf
    {%-elif 'anyOf' in schema-%}
        anyOf
    {%-endif-%}
{%-endmacro-%}

{%-macro ComponentType(schema, index, fullClassPath=None)-%}
    {%-if '$ref' in schema-%}
        {{resolver.py_class_name(schema['$ref'])}}
    {%-else-%}
        self.Component{{index}}
    {%-endif-%}
{%-endmacro-%}

{%-set fullClassPath -%}
    {%-if parentClass is not defined or parentClass is none-%}
        {{Name}}
    {%-else-%}
        {{parentClass}}.{{Name}}
    {%-endif-%}
{%-endset-%}

class {{Name}}(object):
    """This combines {{Combination(schema)}} {{schema[Combination(schema)] |count}} components.
    """

    {%-for comp in schema[Combination(schema)]%}
    {%-if '$ref' not in comp%}
    {%-set compClassName%}Component{{loop.index}}{%endset%}
    {{loader.Class(resolver, compClassName, comp, fullClassPath) |indent(4)}}
    {%-endif%}
    {%-endfor%}

    def __init__(self, *args):
        """Initialization for {{Name}} which combines {{Combination(schema)}} {{schema[Combination(schema)] |count}} components.
        """
        {%-for compSchema in schema[Combination(schema)]%}
        self._component{{loop.index}} = None
        {%-endfor%}
        if len(args) == 1 and isinstance(args[0], type(self)):
            {%-for compSchema in schema[Combination(schema)]%}
            self._component{{loop.index}} = args[0]._component{{loop.index}}
            {%-endfor%}
        elif len(args) == 1:
            {%-for compSchema in schema[Combination(schema)]%}
            try:
                self._component{{loop.index}} = {{ComponentType(compSchema, loop.index)}}(args[0])
            except:
                {%-if Combination(schema) == 'allOf'%}
                raise ValueError("Could not find {{ComponentType(compSchema, loop.index)}} in data")
                {%-else%}
                pass
                {%-endif%}
            {%-endfor%}
        else:
            {%-for compSchema in schema[Combination(schema)]%}
            self._component{{loop.index}} = None
            {%-endfor%}
            for arg in args:
                {%-for compSchema in schema[Combination(schema)]%}
                if self._component{{loop.index}} is None:
                    if isinstance(arg, {{ComponentType(compSchema, loop.index)}}):
                        self._component{{loop.index}} = arg
                    else:
                        try:
                            self._component{{loop.index}} = {{ComponentType(compSchema, loop.index)}}(arg)
                        except:
                            pass
                {%-endfor%}
        {%-if Combination(schema) == 'allOf'%}
        {%-for compSchema in schema['allOf']%}
        if self._component{{loop.index}} is None:
            raise ValueError("Did not provide data for {{ComponentType(compSchema, loop.index)}}")
        {%-endfor-%}
        {%-endif%}
        {%-if schema.requiredProperties | length > 0 %}
        # Test to make sure item can still serialize with the required properties
        self.Serializable()
        {%-endif%}

    {%for compSchema in schema[Combination(schema)]%}
    def GetComponent{{loop.index}}(self):
        return self._component{{loop.index}}

    def SetComponent{{loop.index}}(self, data) -> {{fullClassPath}}:
        if isinstance(data, {{ComponentType(compSchema, loop.index)}}):
            self._component{{loop.index}} = data
        elif isinstance(data, dict):
            self._component{{loop.index}} = {{ComponentType(compSchema, loop.index)}}(data)
        else:
            raise ValueError("Didn't pass an valid representation of {{ComponentType(compSchema, loop.index)}}")
        return self
    {%endfor%}
    def Serializable(self) -> dict:
        obj = {}
        {%-for compSchema in schema[Combination(schema)]%}
        if self._component{{loop.index}} is not None:
            obj.update(self._component{{loop.index}}.Serializable())
        {%-endfor%}
        {%-if schema.requiredProperties | length > 0 %}
        for req_prop in {{schema.requiredProperties |sort}}:
            if req_prop not in obj:
                raise KeyError("Missing required property '{}' in serialized object".format(req_prop))
        {%-endif%}
        return obj

